package nl.unimaas.micc.eventSnookerTest.simulation.event;

import java.awt.Color;
import java.util.HashSet;
import java.util.Set;

import nl.unimaas.micc.eventSnookerTest.domain.BilliardBall;
import nl.unimaas.micc.eventSnookerTest.domain.Ball.BallState;
import nl.unimaas.micc.eventSnookerTest.exec.Tester;
import nl.unimaas.micc.eventSnookerTest.math.Vector3D;
import nl.unimaas.micc.eventSnookerTest.simulation.physics.BallMotion;
import nl.unimaas.micc.eventSnookerTest.simulation.physics.Physics;

public class StateChange extends Event
{
	public StateChange(BilliardBall ball)
	{
		super(ball.getTime() + ball.getState().getMotion().getDuration(ball),toSet(ball));
		this.ball = ball;
		if (ball.getState() == BallState.SLIDING)
		{
			this.newState = BallState.ROLLING;
		}
		else if (ball.getState() == BallState.ROLLING)
		{
			this.newState = BallState.RESTING;
		}
	}

	public BilliardBall getBall()
	{
		return ball;
	}

	public void handle()
	{

		BallMotion motion = ball.getState().getMotion();

		// first calculate the vectors, then store them into the object... the
		// original values are still needed to calculate the new values!
		Vector3D v = motion.getVelocity(ball, getTime());
		Vector3D p = motion.getPosition(ball, getTime());
		Vector3D av = motion.getAngularVelocity(ball, getTime());

		System.out.println("Was " + ball.getState() + ": " + ball);
		//System.out.println("v: " +v+" |v|:"+v.getLength());
		//System.out.println("av: " +motion.getAngularVelocity(ball, getTime())+" |av|:"+motion.getAngularVelocity(ball, getTime()).getLength());
		ball.setTime(getTime());
		ball.setState(newState);
		
		//prevent non null resting state vectors that could occur by rounding errors
		//at the transition to the RESTING state
		if(ball.getState() == BallState.RESTING){
			ball.setAngularVelocity(Vector3D.nullVector());
			ball.setVelocity(Vector3D.nullVector());
		}
		else{
		ball.setAngularVelocity(av);
		ball.setVelocity(v);
		}
		ball.setPosition(p);
		System.out.println("Now " + ball.getState() + ": " + ball);
		
		// Mark event in Tester
		Tester.markPoint(ball.getState().getMotion().getPosition(ball,
				this.getTime()).x, ball.getState().getMotion().getPosition(ball,
						this.getTime()).y, this.toString(), Color.GREEN);
	}
	
	private static Set<BilliardBall> toSet(BilliardBall ball)
	{
		HashSet<BilliardBall> h = new HashSet<BilliardBall>();
		h.add(ball);
		return h;
	}

	private BilliardBall ball;
	private BallState newState;

}
